package mq

import (
	"duanju-mq/pkg/config"
	"duanju-mq/pkg/log"
	"duanju-mq/pkg/redis"
	"duanju-mq/pkg/util/convert"
	"encoding/json"
	"errors"
	"fmt"
	"hash/crc32"
	"strings"
)

var (
	fMQPrefix = config.String("mq.prefix", "AD/MQ/", "mq redis key prefix")
	mqs       = map[string]*MQ{}
)

func Init(names ...string) {
	for _, name := range names {
		mqs[name] = NewMQ(name)
	}
}

func NewMQ(name string) *MQ {
	log.Info("MQ:", name)
	ss := strings.Split(name, "_")
	for i, s := range ss {
		ss[i] = strings.Title(s)
	}
	defKey := *config.String("mq."+name+".key", strings.Join(ss, ""), "mq "+name+" default key")
	mq := &MQ{rcs: []*conn{}}
	config.Sequence("mq."+name, "mq "+name, func(cfg *config.SeqCfg) {
		mq.rcs = append(mq.rcs, &conn{
			key: *cfg.String("key", defKey, "redis key"),
			rc: redis.Connect(&redis.Server{
				Addr:   *cfg.String("addr", "", "redis addr"),
				Pwd:    *cfg.String("pwd", "", "redis pwd"),
				Prefix: *fMQPrefix,
			}),
		})
	})
	return mq
}
func MqCnt(mqName string) int {
	q, ok := mqs[mqName]
	if ok {
		return len(q.rcs)
	} else {
		return 0
	}
}

type MQ struct {
	rcs []*conn
}

type conn struct {
	key string
	rc  *redis.Client
}

func (q *MQ) Index(uuid string) int {
	if len(q.rcs) == 1 {
		return 0
	}
	if len(q.rcs) == 0 {
		return -1
	}
	return int(crc32.ChecksumIEEE([]byte(uuid))) % len(q.rcs)
}

func (q *MQ) Send(index int, msg string) error {
	if index < 0 || index >= len(q.rcs) {
		return errors.New("out of range")
	}
	// log.Info("mq", q.key, index, msg)
	c := q.rcs[index]
	return c.rc.List(c.key).RPush(msg).Error()
}

func (q *MQ) Recv(index int) (string, error) {
	if index < 0 || index >= len(q.rcs) {
		return "", errors.New("out of range")
	}
	c := q.rcs[index]
	return c.rc.List(c.key).LPop().String()
}

func (q *MQ) SendMsg(msg map[string]interface{}) error {
	b, err := json.Marshal(msg)
	if err != nil {
		return err
	}
	uuid := ""
	if v, ok := msg["Uid"]; ok && v != nil {
		if vv, ok := v.(int); ok {
			uuid = convert.ToString(vv)
		}
	}
	return q.Send(q.Index(uuid), string(b))
}

func SendMsg(mq string, msg map[string]interface{}) error {
	q, ok := mqs[mq]
	if !ok {
		return fmt.Errorf("mq", mq, "not found")
	}
	return q.SendMsg(msg)
}

func RecvMsg(mq string, index int) (string, error) {
	q, ok := mqs[mq]
	if !ok {
		log.Err("mq", mq, "not found")
		return "", errors.New("not found")
	}
	return q.Recv(index)
}
